#pragma once

#include <compl.h>

#include <dbg.h>

typedef struct tsnode
{
	struct tsnode *next;
} tsnode_t;

typedef struct
{
	union
	{
#ifdef __amd64__
		struct
		{
			word_t __version;
			union
			{
				word_t tail_flag : 1;
				word_t idx : WORD_WIDTH - 1;
			};
		};
		llword_t head_versioned;
		struct
		{
			word_t version;
			tsnode_t * head;
		};
#elif defined (__aarch64__)
		struct
		{
			//word_t volatile __version;
			union
			{
				word_t tail_flag : 1;
				word_t idx : WORD_WIDTH - 1;
			};
		};

		llword_t head_versioned;
		struct
		{
			tsnode_t *volatile head;
		};
#endif
	} ALIGN(sizeof(llword_t));
} tstack_packed_t;
typedef struct
{
	union
	{
#ifdef __amd64__
		struct
		{
			word_t __version;
			union
			{
				word_t tail_flag : 1;
				word_t idx : WORD_WIDTH - 1;
			};
		};
		llword_t head_versioned;
		struct
		{
			word_t version;
			tsnode_t * head;
		};
#elif defined (__aarch64__)
		struct
		{
			//word_t volatile __version;
			union
			{
				word_t tail_flag : 1;
				word_t idx : WORD_WIDTH - 1;
			};
		};

		llword_t head_versioned;
		struct
		{
			tsnode_t *volatile head;
		};
#endif

	} ALIGN(HDEF_CACHE_LINE_BYTES);
} tstack_t;

SAI tstack_t *tstack_init(tstack_t *p)
{
	p->head = (tsnode_t *)NULL_PTR;
;
	return p;
}

SAI bool_t tstack_is_empty(tstack_t *p){
	return (p->head == NULL_PTR);
}

// #ifdef __amd64__
SAI bool_t __tstack_push_batch(tstack_t *s, tsnode_t *n, tsnode_t *t)
{
	// llword_t head_versioned;
	// word_t version;
	// word_t i = 0;
	tsnode_t *head;
	llsc_t l;

	ld_link(&l, &s->head_versioned);
	// dbg_printf("bcur head %p\n", s->head);
	do
	{
		head = (tsnode_t *)l.rval;
		atm_st(&t->next, head);
		if (st_cond_rel(&l, (word_t)n)){
			// dbg_printf("cur head %p\n", head);
			return TRUE;
		}
	} while (TRUE);

	return FALSE;
}
SAI bool_t __tstack_pop(tstack_t *s, tsnode_t **n)
{
	// llword_t head_versioned;
	// word_t version;
	tsnode_t *head;
	tsnode_t *next;
	// word_t i = 0;
	llsc_t l;

	// pop不用加
	ld_link(&l, &s->head_versioned);

	do
	{
		head = (tsnode_t *)l.rval; 
		if (!head)
		{
			*n = head;
			return TRUE;
		}

		next = atm_ld(&head->next);
		// TODO: to relax
		if (st_cond(&l, (word_t)next))
		{
			// dbg_printf("next %p\n", next);
			*n = head;
			return TRUE;
		}
	} while (TRUE);
	return FALSE;
}
// #else

// SAI bool_t __tstack_push_batch(tstack_t *s, tsnode_t *n, tsnode_t *t)
// {
//	 dword_t head_versioned;
//	 word_t version;
//	 word_t i = 0;
//	 dword_t ret;
//	 tsnode_t *head;
//	 llsc_t l;

//	 ld_link(&l, &s->head_versioned);

//	 do
//	 {
//		 head = (tsnode_t *)l.rval;
//		 // t->next = head;
//		 atm_st(&t->next, head);
//		 // TODO:write memory barrier
//		 if (st_cond_rel(&l, (word_t)n))
//			 return TRUE;
//	 } while (TRUE);

//	 return FALSE;
// }

// SAI bool_t __tstack_pop(tstack_t *s, tsnode_t **n)
// {
//	 dword_t head_versioned;
//	 word_t version;
//	 tsnode_t *head;
//	 tsnode_t *next;
//	 word_t i = 0;
//	 llsc_t l;

//	 // pop不用加
//	 do
//	 {
//		 ld_link(&l, &s->head_versioned);
//		 head = (tsnode_t *)l.rval;
//		 //next = head->lock_next;
//		 if (!head)
//		 {
//			 *n = head;
//			 return TRUE;
//		 }
//		 next = atm_ldacq(&head->next);
//		 // TODO: to relax
//		 if (st_cond(&l, (word_t)next))
//		 {
//			 *n = head;
//			 return TRUE;
//		 }
//	 } while (TRUE);
//	 return FALSE;
// }
// #endif

// 结合 lf 和 blocking
SAI void tstack_push(tstack_t *s, tsnode_t *n)
{
	// fast_path
	__tstack_push_batch(s, n, n);
}

SAI tsnode_t *tstack_pop(tstack_t *s)
{
	tsnode_t *ret;
	__tstack_pop(s, &ret);
	return ret;
}

#define tstack_entry(ptr, type, member) ((type *)((paddr_t)(ptr) - offsetof(type, member)))
